/*
 * Project: Flying Lantern
 * File: CTextureManager.go
 * Desc: Manages/allocates image instances for passing to CRenderer.
 * License: MIT
 */

package fl

import (
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"log"
	"os"
	"strings"
)

type CTextureManager struct {
	mTextures map[string]*sdl.Surface
}

func (t *CTextureManager) Init() {
	t.mTextures = make(map[string]*sdl.Surface, 5)
}

// Loads a directory full of compatible image files. Returns the number of images loaded.
func (t *CTextureManager) LoadDirectory(dir string) int {

	// Open image directory
	f, err := os.Open(dir)
	if err != nil {
		log.Fatalf("CTextureManager -> LoadDirectory(...) : %v", err)
	}

	// Get a list of filenames
	var fileList []os.FileInfo
	fileList, err = f.Readdir(-1)
	if err != nil {
		log.Fatalf("CTextureManager -> LoadDirectory(...) : %v", err)
	}

	// Close our file pointer
	f.Close()

	numFiles := len(fileList)
	numImages := 0

	// loop through the images
	for i := 0; i < numFiles; i++ {

		fileName := fileList[i].Name()
		numImages := 0

		// If we have an invalid image extension or more than one period, die
		filenameIsValid, name, _ := t.IsValidImageName(fileName)

		if filenameIsValid == false {
			log.Fatal("CTextureManager -> LoadDirectory(...) -> Invalid Image Name: " + fileName)
		}

		// If the filename is already taken in our map, die
		if _, ok := t.mTextures[name]; ok {
			log.Fatal("CTextureManager -> LoadDirectory(...) -> Name Collision For: " + fileName)
		}

		// Load the image onto a surface
		image := sdl.Load(dir + fileName)
		if image == nil {
			log.Fatal(sdl.GetError())
		}

		t.mTextures[name] = image
		numImages += 1
	}

	return numImages
}

func (t *CTextureManager) CheckValidImageExtension(extension string) bool {

	// Force extension to lower case
	extension = strings.ToLower(extension)

	// List of valid extensions
	v := []string{"bmp", "pcx", "gif", "jpeg", "jpg", "png", "tga", "tiff"}

	// RETURNS TRUE: If we have a valid extension
	for _, s := range v {
		if extension == s {
			return true
		}
	}

	return false
}

// Load a texture, specifying a filepath and a name. Returns a pointer to the SDL surface of the loaded texture.
func (t *CTextureManager) LoadTexture(filename string, name string) *sdl.Surface {

	// If we have an invalid image extension or more than one period, die
	filenameIsValid, _, _ := t.IsValidImageName(filename)

	if filenameIsValid == false {
		log.Fatal("CTextureManager -> LoadTexture(...) -> Invalid Image Name: " + filename)
	}

	// If the user specified name is taken, die
	if _, ok := t.mTextures[name]; ok {
		log.Fatal("CTextureManager -> LoadTexture(...) -> Texture Name '" + name + "' is taken.")
	}

	// Load the image onto a surface
	image := sdl.Load(filename)
	if image == nil {
		log.Fatal(sdl.GetError())
	}

	t.mTextures[name] = image
	return image
}

// Check to see if a given filename is valid. Returns ( True/False , Filename , Extension)
func (t *CTextureManager) IsValidImageName(filename string) (isValid bool, name string, extension string) {

	// Only file names with a single period allowed
	splitName := strings.Split(filename, ".")
	if len(splitName) != 2 {
		isValid = false
		name = splitName[0]
		extension = splitName[1]
		return
	}

	// Make sure we have a valid image extension
	if t.CheckValidImageExtension(splitName[1]) == false {
		isValid = false
		name = splitName[0]
		extension = splitName[1]
		return
	}

	isValid = true
	name = splitName[0]
	extension = splitName[1]
	return

}

// Get a texture surface by name
func (t *CTextureManager) GetTexture(name string) *sdl.Surface {
	return t.mTextures[name]
}

// Free a texture and unload it
func (t *CTextureManager) FreeTexture(name string) {
	t.mTextures[name].Free()
	delete(t.mTextures, name)
}

// Get pointer to texture map
func (t *CTextureManager) GetAllTextures() map[string]*sdl.Surface {
	return t.mTextures
}

// Free all textures and empty our map
func (t *CTextureManager) FreeAllTextures() {
	for k, _ := range t.mTextures {
		t.FreeTexture(k)
	}
}
